<?php


/** ensure this file is being included by a parent file */
defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );

$_MAMBOTS->registerFunction( 'onAfterStart', 'plgSystemRespondByEmail_onAfterStart' );

	/**
	 * Do the plugin
	 * @return 
	 */
	function plgSystemRespondByEmail_onAfterStart() {
		$return = plgSystemRespondByEmail::onAfterInitialise();
		return $return;
	}
	
class plgSystemRespondByEmail 
{
	/**
	 * 
	 * @return unknown_type
	 */
	function _isInstalled()
	{
		global $mosConfig_absolute_path, $mosConfig_live_site;
		if (!defined("_JEXEC")) { DEFINE('_JEXEC', '1'); }
		if (!defined("JURI_BASE")) { DEFINE('JURI_BASE', $mosConfig_live_site); }
		if (!defined("JPATH_ADMINISTRATOR")) { DEFINE('JPATH_ADMINISTRATOR', JPATH_BASE.DS.'administrator'); }
        if (!defined("_THISCOMPONENT")) { DEFINE("_THISCOMPONENT", 'com_helpdesk');}
		if (!defined("JPATH_COMPONENT_ADMINISTRATOR")) { DEFINE('JPATH_COMPONENT_ADMINISTRATOR', JPATH_ADMINISTRATOR.DS.'components'.DS._THISCOMPONENT); }
        
		$success = false;
		// Require Helpers
		$helpersPath = JPATH_ADMINISTRATOR.DS.'components'.DS.'com_helpdesk'.DS.'helpers';
		$dh  = opendir($helpersPath);
		while (false !== ($filename = readdir($dh))) 
		{
			$fullpath = $helpersPath.DS.$filename;
			$extension = pathinfo( $fullpath, PATHINFO_EXTENSION );
			if (!is_dir( $fullpath ) && file_exists( $fullpath ) && ($extension == 'php') ) 
			{
				require_once(JPATH_BASE.DS."components".DS."com_helpdesk".DS.'helpdesk.class.php');
				require_once( $fullpath );
				require_once('respondbyemail/pop3.class.php');				
				$success = true;
			}
		}
			
		return $success;
	}
	
	/**
	 * Gets a parameter value
	 *
	 * @access public
	 * @return mixed Parameter value
	 * @since 1.5
	 */
	function _getParameter( $name, $default=null ) 
	{
		static $params;
		
		if (!is_object($params))
		{
			$database = HelpDeskConfig::getDBO();
			$folder = strtolower( 'system' );
			$element = strtolower( 'respondbyemail' );
			
			$return = "";
	
			$query = "
				SELECT 
					`params`
				FROM 
					#__mambots
				WHERE 
					`element` = '{$element}'
				AND 
					`folder` = '{$folder}'
			";
			$database->setQuery( $query );
			$mambot = $database->loadObject();
			
			$params = new mosParameters( $mambot->params );			
		}
		
		$return = $params->get( $name, $default );
		return $return;
	}

	/**
	 * 
	 * @return 
	 * @param $message Object
	 */
	function errorMsg( $message )
	{
        $response = '
			<dl id="system-message">
			<dt class="notice"></dt>
			<dd class="notice message fade">
				<ul>'.
				HelpDeskText::_( 'HelpDesk - Respond by Email: ' ).
				$message						
				.'</ul>
			</dd>
			</dl>
			';
		return $response;
	}
	
	/**
	 * 
	 * @return unknown_type
	 */
	function canCheck()
	{
		$success = false;
		$config = &HelpDeskConfig::getInstance();
		$email_check_interval = plgSystemRespondByEmail::_getParameter('email_check_interval', '10');
		$jdate = HelpDeskConfig::getDate();
		$now = $jdate->toMySQL();
		$then = $config->get( 'respondbyemail_intervaldatetime', '0000-00-00 00:00:00' );
		$database = HelpDeskConfig::getDBO();
		$query = " SELECT '{$then}' + INTERVAL {$email_check_interval} MINUTE ";
		$database->setQuery( $query );
		$next = $database->loadResult();
				
		if ($now >= $next)
		{
			$success = true;
			// update config
			unset($table);
			$table = HelpDeskTable::getInstance( 'config', 'Table' );
			$table->load( 'respondbyemail_intervaldatetime' );
			$table->title = 'respondbyemail_intervaldatetime';
			$table->value = $now;
			$table->store();
			
		}
		
		return $success;
	}
	
	/**
	 * 
	 * @return 
	 * @param $pop_server Object
	 * @param $pop_username Object
	 * @param $pop_password Object
	 * @param $delete_email_after_ticket_creation Object
	 */
	function checkEmail()
	{
		//parameters available to the plugin
		$pop_server = plgSystemRespondByEmail::_getParameter('email_pop_server', '');
		$pop_username = plgSystemRespondByEmail::_getParameter('email_account_login', '');
		$pop_password = plgSystemRespondByEmail::_getParameter('email_account_password', '');
		$delete_email_after_ticket_creation = plgSystemRespondByEmail::_getParameter('delete_email_after_ticket_creation', '0');
		$port = plgSystemRespondByEmail::_getParameter('email_port', '110');
		
		$pop3 = new POP3;

		// Connect to mail server
		$do = $pop3->connect( $pop_server, $port );
		if ($do == false) {
			echo plgSystemRespondByEmail::errorMsg($pop3->error);
			return false;
		}

		// Login to your inbox
		$do = $pop3->login($pop_username,$pop_password);

		if ($do == false) {
			echo plgSystemRespondByEmail::errorMsg($pop3->error);
			return false;
		}

		// Get office status (how many emails are waiting)
		$status = $pop3->get_office_status();

		if ($status == false) {
			echo plgSystemRespondByEmail::errorMsg($pop3->error);
			return false;
		}

		$count = $status['count_mails'];

		//get the last check date to compare with current emails
		//last_check_date should be in unix timestamp format
		$last_check_date = plgSystemRespondByEmail::get_last_checked_date();

		//iterate through the emails
		//need to iterate in reverse order to see newest email first
		//then cut off the for loop once an email was sent before the last check time stamp
		for ($i = $count; $i >= 1; $i--) 
		{
			$email = $pop3->get_mail($i);
			
			if ($email == false) {
				echo plgSystemRespondByEmail::errorMsg($pop3->error);
				continue;
			}

			//parse the email
	  		//if the email is before the time stamp break the for loop
	  		//KEY ASSUMPTION: all previous emails have been processed properly, if the connection broke they might not have been
			if (!plgSystemRespondByEmail::parse_email($email, $last_check_date)) 
			{
				break;
	  		}
	  		
	  		//delete the email if it was requested
	  		if ($delete_email_after_ticket_creation) 
	  		{
	  			$pop3->delete_mail($i);
	  		}
		}
		
		//close the pop3 connection
		$pop3->close();
	}
	
	/**
	 * 
	 * @return 
	 * @param $email Object
	 * @param $last_check_date Object
	 */
	function parse_email($email, $last_check_date)
	{
		//this method is set to parse the following strings out of a raw email (RFC 2822)
		//Date: Fri, 3 Oct 2008 16:41:14 -0500
		//From: "User Name" <email@domain.com>
		//Subject: something
		//separte the headers from the message body, and parse the following from the body
		//-! Reply ABOVE THIS LINE to add a comment to the ticket !-
		//{ticketid:xxxx}

		//vars $date, $from, $fromaddress, $subject, $headers, $message, $ticketid
		$date = "";
		$from = "";
		$fromaddress = "";
		$subject = "";
		$headers = "";
		$message = "";
		$ticketid = "";

		//flag for if raw email header is over
		$splittingheaders = true;
		//flag for if "reply before this line" has been hit
		$beforereplyline = true;

		//iterate through the lines of each email
		for ($j = 0; $j < count($email); $j++) 
		{
			if ($splittingheaders) {
				//this is a header
				$headers .= $email[$j] . "\n";

				// parse out the subject
				if (preg_match("/^Subject: (.*)/", $email[$j], $matches)) {
					$subject = $matches[1];
				}

				//parse out the sender name
				if (preg_match("/^From: (.*)/", $email[$j], $matches)) {
					$from = $matches[1];
				}

				//parse out the sender email address
				if ($c = preg_match_all("/(From)(:).*?([\\w-+]+(?:\\.[\\w-+]+)*@(?:[\\w-]+\\.)+[a-zA-Z]{2,7})/is", $email[$j], $matches)) {
					$fromaddress = $matches[3][0];
				}

				//parse out date for timestamp storage
				if (preg_match("/^Date: (.*)/", $email[$j], $matches)) {
					$date = $matches[1];
					$date = strtotime($date); //convert the date to unix timestamp
					
					//break here if the date was too long ago
					if($date <= $last_check_date) {
						return false;
					}
					
					//pass the date off to see if it is the most recent to update the date
					plgSystemRespondByEmail::set_last_checked_date($date);

				}
			} else {
				//not a header, but part of the message
				//test to see if this line is the -! Reply Before line
				$regex1 = "#-!(.*?)!-#s";
				if ( preg_match_all($regex1, $email[$j], $replymatches) ) {
					// echo '<pre>';
						// print_r($replymatches);
					// echo '</pre>';
					$beforereplyline = false;
			
				}
				
				$regex2 = "#{ticketid:(.*?)}#s";
				if ( preg_match_all($regex2, $email[$j], $ticketmatches) ) {
					// echo '<pre>';
						// print_r($ticketmatches);
					// echo '</pre>';
					$ticketid = $ticketmatches[1][0];
				}

				//only add the content to the message if its before the reply line
				$isHeader = plgSystemRespondByEmail::isHeader( $email[$j] );
				if (!$isHeader && $beforereplyline) 
				{
					// TODO some emails not being parsed nicely
					$message .= $email[$j] . "\n";
				}

			}

			if (trim($email[$j]) == "<MESSAGE>") 
			{
				// pop3.class uses this to signify start of actual email message
				// and end of headers
				$splittingheaders = false;
			}
		}
		
		if (empty($ticketid))
		{
			// if all headers processed and no ticketid present, creating new ticket
			if (($beforereplyline == false)) 
			{
				$newticket = true;
				if ( $checkInputs = plgSystemRespondByEmail::checkInputs($newticket, $from, $fromaddress, $date, $subject, $message) ) 
				{
					plgSystemRespondByEmail::createTicketFromEmail($from, $fromaddress, $date, $subject, $message);
				}
			}			
		} else {
			// if all headers processed and a ticketid present, adding comment to existing ticket
			if (($beforereplyline == false)) 
			{
				if ( $checkInputs = plgSystemRespondByEmail::checkInputs($ticketid, $from, $fromaddress, $date, $subject, $message) ) 
				{
					plgSystemRespondByEmail::addCommentFromEmail($ticketid, $from, $fromaddress, $date, $subject, $message);
				}
			}			
		}
		
		return true;
	}
	
	/**
	 * 
	 * @return 
	 * @param $ticketid Object
	 * @param $from Object
	 * @param $fromaddress Object
	 * @param $date Object
	 * @param $subject Object
	 * @param $message Object
	 */
	function checkInputs ($ticketid, $from, $fromaddress, $date, $subject, $message) 
	{
		$success = false;

		if (
			!empty($ticketid) && 
			!empty($from) && 
			!empty($fromaddress) && 
			!empty($date) && 
			!empty($subject) && 
			!empty($message)
		) {
			$success = true;
		}
		
		return $success;
	}
	
	/**
	 * Get the last checked date from the database, unix time stamp format
	 * 
	 * @return 
	 */
	function get_last_checked_date()
	{
		$return = '';
		
		// Use HelpDeskConfig to store & retrieve lastchecked from the __helpdesk_config table
		$config = HelpDeskConfig::getInstance();
		$lastchecked = $config->get( 'respondbyemail_lastchecked' );
		
		if (isset($lastchecked)) 
		{
			$return = $lastchecked;
		}
		
		return $return;
	}
	
	/**
	 * take a date and see if it needs to be set to the last checked date, unix time stamp format
	 * 
	 * @return 
	 * @param $date Object
	 */
	function set_last_checked_date($date)
	{
		if ($date > plgSystemRespondByEmail::get_last_checked_date()) 
		{						
			$table = HelpDeskTable::getInstance( 'config', 'Table' );
			$table->load( 'respondbyemail_lastchecked' );
			$table->title = 'respondbyemail_lastchecked';
			$table->value = $date;
			$table->store();
		}
	}

	/**
	 * 
	 * @param $address
	 * @return unknown_type
	 */
	function getUserFromEmail( $address )
	{
		$database = HelpDeskConfig::getDBO();

		$query = "
			SELECT 
				* 
			FROM 
				#__users 
			WHERE 
				`email` = '{$address}' 
			LIMIT 1
		";
		$database->setQuery( $query );
		$data = $database->loadObject();
		
		return $data;
	}
	
	/**
	 * adds a comment
	 * @return boolean yes/no on success/fail
	 */
	function addCommentFromEmail($ticketid, $from, $fromaddress, $date, $subject, $emailmessage) 
	{
		$mainframe = HelpDeskConfig::getApplication();
		
		// grab config settings for sender name and email
			$config 		= HelpDeskConfig::getInstance();
			$failFrom 		= $config->get( 'emails_defaultemail', $mainframe->getCfg('mailfrom') );
			$failFromName 	= $config->get( 'emails_defaultname', $mainframe->getCfg('fromname') );
			
		//prepare the message body
			$emailmessage = strval( htmlspecialchars ($emailmessage) );
		
		// get a user object from the email address
			$emailUser = plgSystemRespondByEmail::getUserFromEmail( $fromaddress );

		// If email address not found or not associated with ticket, send message saying comment not added
			if (!isset($emailUser->id) || empty($emailUser->id))
			{
				// break if the email address isnt registered in the joomla database
				$failSubject = HelpDeskText::_( "Comment not added to ticket" );
				$failBody = HelpDeskText::_( "Email unrecognized" );
				$sendFailMessage = plgSystemRespondByEmail::_sendMail( $failFrom, $failFromName, $fromaddress, $failSubject, $failBody );
				return false;
				
			}
		
		// break if the user is not associated with ticket
			if (!$canview = HelpDeskHelperHelpDesk::canViewTicket( $ticketid, $emailUser->id )) 
			{
				$failSubject = HelpDeskText::_( "Comment not added to ticket" );
				$failBody = HelpDeskText::_( "Email not associated with ticket" );
				$sendFailMessage = plgSystemRespondByEmail::_sendMail( $failFrom, $failFromName, $fromaddress, $failSubject, $failBody );
				return false;
			}
		
		// include the HelpDesk table path
			unset($message);
			$message = HelpDeskTable::getInstance( 'message', 'Table' );

		// setup new message
			$message->ticketid			= $ticketid;
			$message->userid_from		= $emailUser->id;
			$message->username_from		= $emailUser->username;
			$message->message			= $emailmessage;	
			$message->priority			= '0';
		
		// date = date + (gmtdate-now)
			$jdate = HelpDeskConfig::getDate();
			$storedate = $date + ($jdate->toUnix() - time() );
			$message->datetime = date("Y-m-d H:i:s", $storedate);

		//add the message to the database
			$message->store();
	
		//update the ticket
			unset($ticket);
			$ticket = HelpDeskTable::getInstance( 'ticket', 'Table' );
			$ticket->load( (int) $ticketid );
			$ticket->status						= 0; // make pending again
			$ticket->last_modified_datetime 	= date("Y-m-d H:i:s", $storedate);		
			$ticket->store();
		
			// send emails to ppl associated with ticket
			// by firing plugin
			$ticket->comment = $emailmessage;
			$msg = new stdClass();
			$msg->type 		= '';
			$msg->message 	= '';
			HelpDeskHelperPlugin::importPlugin( 'helpdesk' );
			$dispatcher = HelpDeskHelperPlugin::getInstance();
			$dispatcher->trigger( 'onAfterAddCommentSuccess', array( $ticket, $emailUser, $msg ) );
				
		return $ticket;
	}
	
	/**
	 * adds a comment
	 * @return boolean yes/no on success/fail
	 */
	function createTicketFromEmail( $from, $fromaddress, $date, $subject, $emailmessage ) 
	{
		$success = false;
		$mainframe = HelpDeskConfig::getApplication();
		
		// Check param for whether/not creating tickets from recognized emails
		$create_tickets = plgSystemRespondByEmail::_getParameter( 'create_tickets', '1');
		// Check param for whether/not creating tickets from unrecognized emails
		$create_tickets_unrecognized = plgSystemRespondByEmail::_getParameter( 'create_tickets_unrecognized', '0');

		if (!$create_tickets && !$create_tickets_unrecognized)
		{
			return $success;
		}
		
		// get a user object from the email address
			$emailUser = plgSystemRespondByEmail::getUserFromEmail( $fromaddress );
			
		if (empty($emailUser->id) && !$create_tickets_unrecognized)
		{
			return $success;
			
		} elseif (empty($emailUser->id) && $create_tickets_unrecognized)
		{
			// create the user object		
				$newuser_email = $fromaddress;
				$exploded = explode('@', $fromaddress);
				$newuser_username = @$exploded['0'];
				$newuser_name = $from;
				
				$msg = new stdClass();
				$msg->type 		= '';
				$msg->message 	= '';
				
				$details = array();
				$details['name'] 		= $newuser_name;
				$details['username'] 	= $newuser_username;
				$details['email'] 		= $newuser_email;
				$details['password'] 	= HelpDeskHelperUser::genRandomPassword();
				$details['password2'] 	= $details['password'];
				if ($emailUser = HelpDeskHelperUser::createNewUser( $details, $msg )) 
				{
					// cool
				}
				if ( !$emailUser || !isset($emailUser->id) ) 
				{
		        	// not cool
		        	return $success;
				}
		}
		
		// grab config settings for sender name and email
			$config 		= HelpDeskConfig::getInstance();
			$failFrom 		= $config->get( 'emails_defaultemail', $mainframe->getCfg('mailfrom') );
			$failFromName 	= $config->get( 'emails_defaultname', $mainframe->getCfg('fromname') );
			
		//prepare the message body
			$emailmessage = strval( htmlspecialchars ($emailmessage) );

		// setup the date
			$jdate = HelpDeskConfig::getDate();
			$storedate = $date + ($jdate->toUnix() - time() );
			
		// create the ticket
			unset($ticket);
			$ticket = HelpDeskTable::getInstance( 'ticket', 'Table' );
			$ticket->status					= '0'; 
			$ticket->last_modified_by		= $emailUser->id;
			$ticket->last_modified_datetime	= date("Y-m-d H:i:s", $storedate);
			$ticket->created_datetime		= date("Y-m-d H:i:s", $storedate);
			$ticket->created_by	 			= $emailUser->id;
			$ticket->sender_email 			= $emailUser->email;
			$ticket->sender_userid 			= $emailUser->id;
			$ticket->sender_flag_read		= '0';
			$ticket->store();			
			
		// send emails to ppl associated with ticket
			// by firing plugin
			$ticket->comment = $emailmessage;
			$msg = new stdClass();
			$msg->type 		= '';
			$msg->message 	= '';
			HelpDeskHelperPlugin::importPlugin( 'helpdesk' );
			$dispatcher = HelpDeskHelperPlugin::getInstance();
			$dispatcher->trigger( 'onAfterSaveSuccess', array( $ticket, $emailUser, $msg ) );
				
		return $ticket;
	}

	/**
	 *
	 * Method is called onAfterInitialise
	 *
	 */
	function onAfterInitialise() 
	{	
		if (!plgSystemRespondByEmail::_isInstalled()) 
		{
			return null;
		}

		if ($canCheck = plgSystemRespondByEmail::canCheck())
		{
			$success = plgSystemRespondByEmail::checkEmail();	
		}
		
		return null;
	}
	
	/**
	 * 
	 * @return 
	 * @param $line Object
	 */
	function isHeader( $line )
	{
		$success = false;
		
			if(eregi("Message-ID",$line)){
				$success = true;
			}
			if(eregi("Content-Type",$line)){
				$success = true;
			}
			if(eregi("Content-Transfer-Encoding",$line)){
				$success = true;
			}
			if(eregi("MIME-Version",$line)){
				$success = true;
			}
			if(eregi("Reply-To",substr($line,0,8))){
				$success = true;
			}
			if(eregi("X-Mailer",$line)){
				$success = true;
			}
			if(eregi("X-Priority",$line)){
				$success = true;
			}
			if(eregi("Mail-Followup-To",$line)){
				$success = true;
			}
			if(eregi("Mail-Reply-To",$line)){
				$success = true;
			}
			if(eregi("Return-Receipt-To",$line)){
				$success = true;
			}
			if(eregi("Disposition-Notifaction-To",$line)){
				$success = true;
			}
			if(eregi("------=",$line)){
				$success = true;
			}
			if(eregi("Content-Disposition",$line)){
				$success = true;
			}
			
		return $success;
	}
	
	/**
	 * 
	 * @return unknown_type
	 */
	function _sendMail( $from, $fromname, $recipient, $subject, $body, $actions=NULL, $mode=NULL, $cc=NULL, $bcc=NULL, $attachment=NULL, $replyto=NULL, $replytoname=NULL ) 
	{
		$success = false;
		$message = HelpDeskHelperEmail::getMailer();
		$message->addRecipient( $recipient );
		$message->setSubject( $subject );
		$message->setBody( $body );
		$sender = array( $from, $fromname );
		$message->setSender($sender);
		$sent = $message->send();
		if ($sent == '1') {
			$success = true;
		}
		return $success;
	}
}